#include "Lecturer.h"
#include <limits>
#include <iomanip>

using namespace std;

Lecturers::Lecturers(Database dbInput):Users(dbInput)
{
}

void Lecturers::lectMenu()
{
	int opt;
    string startDate, endDate;

	cout << "Welcome to A-Star Global! " << endl 
	 	 << "Hi, " << fullName << "!" << endl << endl;
	
	while (opt != 8)
	{	
		bool check = false;
		cout << "My Menu" << endl 
			 << "===========================" << endl << endl;
		cout << "1) Add student to module" << endl;
		cout << "2) Add student to class" << endl;
		cout << "3) Remove student from class" << endl;
		cout << "4) Update attendance" << endl;
		cout << "5) Add notice" << endl;
		cout << "6) Add a class" << endl;
		cout << "7) Delete a class" << endl;
		cout << "8) Send Summary Report" << endl;
		cout << "9) Change Password" << endl;
        cout << "10) Quit" << endl << endl;
		
		while (!check)
		{
			cout << "Please enter your choice: " ;
			cin >> opt;
			if (cin.fail())
			{
				cin.clear();
				cin.ignore(numeric_limits<streamsize>::max(), '\n');
			}
			else
			{
				check = true;
			}
		}
		
		switch (opt)
		{
			case 1: addStudentToModule();
					break;
			case 2: addStudentToClass();
					break;
			case 3: removeStudentFromClass();
					break;
			case 4: updateAbsentee();
					break;	
			case 5: updateNotice();
					break;
			case 6: addClass();
					break;
			case 7: deleteClass();
					break;
            case 8: cin.ignore();
            		cout << "Start Date (YYYY-MM-DD HH:MM): ";
                    getline(cin, startDate);
                    cin.clear();
                    cin.sync();
                    cout << "End Date (YYYY-MM-DD HH:MM): ";
                    getline(cin, endDate);
                    cin.clear();
                    cin.sync();
                    cout << endl;
                    summaryReport(startDate, endDate);
                    break;
            case 9: changePassword();
            		break;
            case 10: cout << "Good Bye!" << endl;
                    exit(0);
                    break;
			default: cout << "Invalid choice" << endl;
		}
	}
}

//add a student to a module
void Lecturers::addStudentToModule()
{
	string studentName;
	string modCode;
	string grp;
	bool check = false;
	
	cin.ignore();
	while(!check)
	{
		cout << "Please enter the module code or 'exit' to return to menu: ";
		getline(cin, modCode);
		if (modCode == "exit")
			lectMenu();
		else if (modCode != "")
		{
			//check if the lecturer teaches the module
			bool correctModuleCode = checkLECTURERSMODULEModuleCode(modCode);
			if (correctModuleCode)
				check = true;
			else
				cout << "You are not teaching that module! Please enter other module code." << endl << endl; 
		}
	}
	
        //show all the students from database
	displayAllStudentFromDB();
	//get student name from user
	while(check)
	{
		cout << "Please enter the fullname of the students or enter 'exit' to go back to menu: ";
		getline(cin, studentName);
		if (studentName == "exit")
			lectMenu();
		else if (studentName != "")
			check = false;
		else
			cout << "Please do not leave it empty!" << endl;
	}
	
	//get the lecture group from user
	while(!check)
	{
		cout << "Please enter the group of the students or 'exit to return to menu: ";
		getline(cin, grp);
		if (grp == "exit")
			lectMenu();
		else if (grp != "")
			check = true;
		else
			cout << "Please do not leave it empty!" << endl;
	}
	//check if student already in module
	bool studentInModule = checkStudentInModule(studentName, modCode);
	if (!studentInModule)
	{
		string statement = "insert into STUDENTS_MODULES ";
		statement += "(sm_id, fullname, module_code, `group`) ";
		statement += "values (NULL, '"+studentName+"','"+modCode+"','"+grp+"'); ";
		db.query(statement);	//insert the record to database
		//check if student in the module
		bool studentAdded = checkStudentInModule(studentName, modCode);
		if (studentAdded)
			cout << endl << "Student added" << endl << endl;
		else
			cout << endl << "Student not added" << endl << endl;
	}
	else 
	{
		cout << endl << "The student is already in the class!" << endl << endl; 
	}
}

void Lecturers::addStudentToClass()
{
	vector <vector<string> > listOfClass;
	bool check = true;
	string lessID, name;
	
	//show all lesson user has
	displayUserLessons();
	lessID = getLessonID();
	//get the module code of the lesson
	string module = getModuleCodeFromLESSONS(lessID);
	//show all students taking the module
	displayFullNameFromStudentModule(module);
	//get the name of the student
	while(check)
	{
		cout << "Please enter the student name or enter 'exit' to go back to menu: ";
		getline(cin, name);
		if (name == "exit")
			lectMenu();
		else if (name != "")
		{
			// vector <vector<string> >temp = db.query("select fullname from STUDENTS_MODULES where fullname = '"+name+"' and module_code = '"+mod+"'; ");
			bool isNameInModule = checkStudentInModule(name, module);
			bool isNameInClass = checkStudentInClass(name, lessID);
                        if (isNameInModule)
                            if (!isNameInClass)
                                check = false;
                            else
                                cout << "Student already exist in class! Please enter other name." << endl;
			else
				cout << "The student not found! Please enter another student. " << endl;
		}
	}
	//insert the data into STUDENTS_LESSONS table
	string statement = "insert into `STUDENTS_LESSONS` ";
	statement += "(sl_id, fullname, lessons_id) values (NULL, '"+name+"','"+lessID+"'); ";
	db.query(statement);
	//check if student is in the lesson
	bool isStudentInClass = checkStudentInClass(name, lessID);
	if (isStudentInClass)
		cout << "Student " << name << " added to lesson " << lessID << " successuflly" << endl << endl; 
	else
		cout << "Students not added.";
}

void Lecturers::removeStudentFromClass()
{
	bool check = false;
	string lessID, name;
	
	//show all the lessons that user has
	displayUserLessons();
	lessID = getLessonID();
	//get the module code for the lesson
	string module = getModuleCodeFromLESSONS(lessID);
	//show all the students in the lesson
    displayFullNameFromStudentLesson(lessID);
	//get the name of the student
	while(!check)
	{
		cout << "Please enter the student name or enter 'exit' to go back to menu: ";
		getline(cin, name);
		if (name == "exit")
			lectMenu();
		else if (name != "")
		{
			//check if the student is in lesson
			bool studentInClass = checkStudentInClass(name, lessID);
			if (studentInClass)
				check = true;
			else
				cout << "The student not found! Please enter another student. " << endl << endl;
		}
	}
	//delete the record from STUDENTS_LESSONS table
	db.query("delete from STUDENTS_LESSONS where fullname = '"+name+"' and lessons_id = '"+lessID+"'; ");
	//check if the student is in lesson
	bool studentInClass = checkStudentInClass(name, module);
	if (!studentInClass)
		cout << endl << "The student " << name << " is removed from lesson " << lessID << " successfully." << endl << endl;
	else
		cout << endl << "Student not removed from class!" << endl << endl;
}

void Lecturers::updateAbsentee()
{
	bool check = false;
	string lessID, name, slid;
	
	//show all the lessons that the user has
	displayUserLessons();
	lessID = getLessonID();
	//show all the students from the lesson
	displayFullNameFromStudentLesson(lessID);
	//get the name of student
	while(!check)
	{
		cout << "Please enter the ABSENT student name or 'exit' to go back to menu: ";
		getline(cin, name);
		if (name == "exit")
			lectMenu();
		else if (name != "")
		{
			//check if the student is in the class
			bool studentInClass = checkStudentInClass(name, lessID);
			if (studentInClass)
			{
				//get the student_lesson id from STUDENTS_LESSONS
				slid = getSlIdFromSTUDENTLESSONS(name, lessID);
				check = true;
			}
			else
				cout << "The student name not found! Please enter another student name. " << endl;
		}
	}
	//insert into the database the absentee record
	db.query("insert into `ABSENTEES` (absentees_id, sl_id, reasons) values (NULL, '"+slid+"', NULL);");
	//check if the student is already in the absentee list
	bool studentAbsent = checkStudentInAbsentee(name);
	if (studentAbsent)
		cout << endl << "Absentee added successfully!" << endl << endl;
	else
		cout << endl << "Absentee not added!" << endl << endl;
}

void Lecturers::updateNotice()
{
	string lessID, notice;
	
	//show all the lessons that the user have
	displayUserLessons();
	lessID = getLessonID();
	
	cout << "Please enter the notice or 'exit' to return to menu: ";
	getline(cin, notice);
	if (notice == "exit")
		lectMenu();
	db.query("update `LESSONS` SET notice = '"+notice+"'where lessons_id = '"+lessID+"';");
	cout << "Notice added!" << endl << endl;
}

void Lecturers::addClass()
{
	bool check = false;
	string modCode, ptid, venueName, timeSlot, lessonID;
	
	//get the module code
	while (!check)
	{
		cin.ignore();
		cout << "Please enter module code or 'exit' to return to menu: " ;
		getline(cin, modCode);
		if (modCode == "exit")
			lectMenu();
		bool isLecturerModule = checkLECTURERSMODULEModuleCode(modCode);
		if(isLecturerModule)
			check = true;
		else
			cout << "You are not teaching this module! Please enter another module" << endl;
	}
	//get the venue name, date and time of lesson
	while (check)
	{
		cout << "Please enter venue name or 'exit' to return to menu: " ;
		getline(cin, venueName);
		if (venueName == "exit")
			lectMenu();
		cout << "Please enter time and date (YYYY-MM-DD HH:MM) or 'exit' to return to menu: ";
		getline (cin, timeSlot);
		if (timeSlot == "exit")
			lectMenu();
		bool isVenueAvailable = checkIsVenueAvailable(venueName, timeSlot);
		if(isVenueAvailable)
		{	
			string statement = "insert into `place_time` (pt_id, venue, timeslot) " ;
			statement += "values (NULL, '"+venueName+"', '"+timeSlot+"') ;";
			db.query(statement);
			ptid = getPtIdFromPLACETIME(venueName, timeSlot);
			check = false;
		}
		else
		{
			cout << "The location at the time is booked by others." << endl;
			cout << "Please select another venue/time slot." << endl;
		}
	}
    //get the lesson id
	while(!check)
	{
		cout << "Please enter lesson id or 'exit' to return to menu: " << endl;
		getline(cin, lessonID);
		if (lessonID == "exit")
			lectMenu();
		cin.clear();
		cin.sync();
		bool recordFound = checkForLessonsId(lessonID);
		if (!recordFound)
		   check = true;
		else
			cout << "Lesson already exist!" << endl;
	}
    
	//insert data in to the lessons table
	string statement = "insert into `LESSONS` (lessons_id, module_code, pt_id, notice) ";
	statement += "values ('"+lessonID+"', '"+modCode+"', '"+ptid+"', NULL );";
	db.query(statement);
	//check if the lesson exist
	bool lessonFound = checkForLessonsId(lessonID);
    if (lessonFound)
	{
		//insert data into lecturers_lessons table
		string statement = "insert into `LECTURERS_LESSONS` (ll_id, fullname, lessons_id) ";
		statement += "values (NULL, '"+fullName+"', '"+lessonID+"'); ";
		db.query(statement);
		cout << endl << "Class is added successfully!" << endl;
	}
	else
		cout << endl << "The lesson does not exist." << endl;
}

void Lecturers::deleteClass()
{
	bool check = false;
	string lessID;
	
	//show all the classes the lecturer has
	displayUserLessons();
	lessID = getLessonID();
	//check if the lesson exist
	bool recordFound = checkForLessonsId(lessID);
	if(recordFound)
	{
		//delete from LESSONS and LECTURERS_LESSONS table
		db.query("delete from LESSONS where lessons_id = '"+lessID+"' ;");
		db.query("delete from LECTURERS_LESSONS where lessons_id = '"+lessID+"' ;");
		cout << "lesson has been successfully deleted ..." <<endl;
	}
	else
		cout << "Class not deleted!" << endl << endl;
}

void Lecturers::summaryReport(string startDate, string endDate)
{
	bool checkMailSent = false;
	string statement ="SELECT sl.fullname, count(sl.fullname), temp.module_code FROM ";
	statement        +="(SELECT temp.lessons_id, temp.module_code FROM ";
	statement        +="(SELECT l.lessons_id, l.module_code, l.pt_id FROM LESSONS l ";
	statement        +="INNER JOIN LECTURERS_MODULES lm ";
	statement        +="ON l.module_code = lm.module_code ";
	statement        +="WHERE fullname = '"+fullName+"')temp ";
	statement        +="INNER JOIN PLACE_TIME pt ";
	statement        +="ON temp.pt_id = pt.pt_id ";
	statement        +="WHERE strftime ('%Y-%m-%d', timeslot) BETWEEN strftime ('%Y-%m-%d', '"+startDate+"') ";
	statement        +="AND strftime ('%Y-%m-%d', '"+endDate+"') )temp ";
	statement        +="INNER JOIN STUDENTS_LESSONS sl ON sl.lessons_id = temp.lessons_id WHERE NOT EXISTS (SELECT sl_id FROM ABSENTEES a WHERE sl.sl_id = a.sl_id)";
	statement        +="group by sl.fullname, temp.module_code; ";

	vector<vector<string> > listOfStudents=db.query(statement);

	cout << "Sending Email to students who did not meet attendance requirements..." << endl << endl;

	for (int i=0; i<listOfStudents.size();i++ )
	{

		vector<string> temp = listOfStudents[i];

		vector<vector<string> > listOfEmailAdd=db.query("SELECT email FROM USERS WHERE fullname = '"+temp[0] + "';");
		double hoursAttended = atof(temp[1].c_str()) * 3 ;

		double totalHoursForModule = totalHours(startDate, endDate, temp[2]);// vector<vector<string> > totalHours = db.query("SELECT total_hours FROM MODULES WHERE module_code = '"+temp[2]+"';");

		cout << "Email sent to " << temp[0] << endl;

		double percentage = (hoursAttended / totalHoursForModule ) * 100;

		if( percentage < 75)
		{
			sendEmail(75, temp[2], listOfEmailAdd[0][0]);
			checkMailSent = true;
		}
		else if (percentage < 80)
		{
			sendEmail(80, temp[2], listOfEmailAdd[0][0]);
			checkMailSent = true;
		}
		else if (percentage < 90)
		{
			sendEmail(90, temp[2], listOfEmailAdd[0][0]);
			checkMailSent = true;
		}
	}

	if (checkMailSent = false)
		cout << "No Emails Sent..." << endl << endl;

	cout << endl;
	lectMenu();
}
void Lecturers::changePassword() {

	string newPassword, newPassword2;
	bool valid = false;

	while(!valid) {

		cout << "Enter your new password: ";
		cin >> newPassword;
		cout << "Re-confirm your new password: ";
		cin >> newPassword2;

		valid = checkPassword (newPassword, newPassword2);

		if (valid == true) {
			db.changePassword (newPassword);
			cout << "Password successfully changed.." << endl;
		}
	}
	lectMenu();
}

bool Lecturers::checkPassword (string pass1, string pass2) {

	bool alphaPresent = false;
	bool numPresent = false;

	if (pass1 == pass2) {

		for (int i = 0; i < pass1.length(); i++) {
			//check if password contain alphabets
			if (isalpha(pass1[i]))
				alphaPresent = true;
			//check if password contain digits
			else if (isdigit(pass1[i]))
				numPresent = true;
			//check if password contain non alphanumeric characters
			else {
				cout << "Invalid character. Please key in again." << endl << endl;
				return 0;
			}
		}
		//if password is valid (contains at least 1 letter and 1 digit)
		if (alphaPresent == true && numPresent == true && pass1.length() >= 8)
			return 1;
		
		else 
			cout << "Password needs to 8 characters long and contain at least 1 digit and 1 letter. Please key in again." << endl << endl;
			return 0;
	}
	//if input password and reconfirmed password is not the same
	else {

		cout << "Password does not match. Please key in again." << endl << endl;
		return 0;
	}

}

void Lecturers::displayUserLessons()
{
	vector <vector<string> > listOfClass;
	string statement = "select ls.ll_id, ls.lessons_id, l.module_code from LECTURERS_LESSONS ls, LESSONS l ";
	statement += "where ls.fullname= '"+fullName+"' and l.lessons_id = ls.lessons_id; "; 
	
	//get the classes that the lecturer is teaching
	listOfClass = db.query(statement);
	if (listOfClass.size() == 0)
	{
		cout << "You do not have any lessons!" << endl;
	}
	else 
	{
		cout << endl << "These are the list of lesson that you have:" << endl;
        cout << endl << setw(8) << left << "S/N" << setw(15) << left << "Lesson ID" << setw(20) << left << "Module Code" << endl;
		cout << "===============================================" << endl;
		for (vector<vector<string> >:: iterator it = listOfClass.begin(); it < listOfClass.end(); ++it)
		{
			vector< string > row = *it;
			cout << setw(8) << left << row.at(0) << setw(15) << left << row.at(1) << setw(20) << left << row.at(2) << endl;
		}
	}

	cout << endl;
}

void Lecturers::displayAllStudentFromDB()
{
	//get from the database all the students and display
	vector < vector<string> > listOfStudents = db.query ("select fullname from users where type = 'STUDENT';");
	cout << endl << setw(25) << left << "Full Name" << endl; 
	cout << "=====================" << endl;
        for (vector<vector<string> >:: iterator it = listOfStudents.begin(); it < listOfStudents.end(); ++it)
	{
		vector< string > row = *it;
		cout << setw(25) << left << row.at(0) << endl;
	} 

	cout << endl; 
}

void Lecturers::displayFullNameFromStudentModule(string mod)
{
	string statement = "select fullname, `group` from STUDENTS_MODULES ";
	statement += "where module_code = '"+mod+"'; ";
	vector <vector<string> > listOfStudInMod = db.query(statement);

    cout << endl << setw(25) << left << "Full Name" << setw(8) << left << "Group" << endl;
    cout << "==========================================" << endl;
	for (vector <vector<string> >:: iterator it = listOfStudInMod.begin(); it < listOfStudInMod.end(); ++it)
	{
		vector <string> row = *it;
		cout << setw(25) << left << row.at(0) << setw(8) << left  << row.at(1) << endl;
	}

	cout << endl;
}

void Lecturers::displayFullNameFromStudentLesson(string lessID)
{
	string statement = "select distinct sl.fullname, sm.`group` from STUDENTS_LESSONS sl, STUDENTS_MODULES sm ";
	statement += "where sl.lessons_id = '"+lessID+"' and sm.fullname = sl.fullname; ";
	vector <vector<string> > listOfStudInLesson = db.query(statement);
    cout << endl << setw(25) << left << "Full Name" << setw(8) << left << "Group" << endl;
    cout << "==========================================" << endl;
	for (vector <vector<string> >:: iterator it = listOfStudInLesson.begin(); it < listOfStudInLesson.end(); ++it)
	{
		vector <string> row = *it;
		cout << setw(25) << left << row.at(0) << setw(8) << left  << row.at(1) << endl;
	}

	cout << endl;
}

void Lecturers::sendEmail(int percentage, string moduleCodeInput, string emailInput)
{
	stringstream ss;
	string message;
	ss << percentage;
	ss >>message;
	db.query("INSERT INTO EMAILS (mail_id, email, mail) values (NULL, '"+emailInput+"', 'Your attendance is below "+message+" for Module: "+moduleCodeInput+"');");
}

bool Lecturers::checkLECTURERSMODULEModuleCode(string modCode)
{
	string statement = "select lm_id from LECTURERS_MODULES ";
	statement += "where module_code = '"+modCode+"' and fullname= '"+fullName+"';";
	vector < vector<string> > checkMod = db.query(statement);
	if (checkMod.size() != 0)
		return true;
	else
		return false;
}

bool Lecturers::checkStudentInModule(string studentName, string modCode)
{
	string statement = "select sm_id from STUDENTS_MODULES ";
	statement += "where fullname = '" + studentName +"' and module_code = '"+ modCode +"'; ";
	vector < vector<string> > temp = db.query (statement);
	if (temp.size() == 0)
		return false;
	else
		return true;
} 

bool Lecturers::checkStudentInClass(string name, string lessID)
{
	string statement = "select sl_id from STUDENTS_LESSONS ";
	statement += "where fullname = '"+name+"' and lessons_id = '"+lessID+"'; ";
	vector<vector<string> > temp = db.query(statement);
	if (temp.size() == 0)
		return false;
	else
		return true;
}

bool Lecturers::checkStudentInAbsentee(string name)
{
	string statement = "select a.sl_id from ABSENTEES a, STUDENTS_LESSONS sl ";
	statement += "where sl.fullname = '"+name+"' and a.sl_id = sl.sl_id; ";
	vector < vector<string> > temp = db.query(statement);
	if (temp.size() == 0)
		return false;
	else
		return true;
}	

bool Lecturers::checkIsVenueAvailable(string venueName, string timeSlot)
{
	string statement = "select pt_id from place_time ";
	statement += "where venue = '"+venueName+"' and strftime ('%Y-%m-%d %H:%M',timeslot) = '"+timeSlot+"' ;";
	vector <vector<string> > temp = db.query(statement);
	if (temp.size()== 0)
		return true;
	else
		return false;
}	

bool Lecturers::checkForLessonsId(string lessonID)
{
    vector<vector<string > > tempID = db.query("select lessons_id from LESSONS where lessons_id = '"+lessonID+"';");
    if (tempID.size() == 0)
        return false;
    return true;
}

string Lecturers::getSlIdFromSTUDENTLESSONS(string name, string lessID)
{
	string statement = "select sl_id from STUDENTS_LESSONS ";
	statement += "where fullname = '"+name+"' and lessons_id = '"+lessID+"'; ";
	vector < vector<string> > temp = db.query(statement);
	return temp[0].at(0);
}

string Lecturers::getModuleCodeFromLESSONS(string lessID)
{
	vector <vector<string> > modTemp = db.query("select module_code from LESSONS where lessons_id = '"+lessID+"' ;");
	string mod = modTemp[0].at(0);
	return mod;
}

string Lecturers::getLessonID()
{
	bool check = true;
	string lessID = "";

	while(check)
	{
		cin.ignore();
		cout << "Please enter the lesson id or 'exit' to go back to menu: ";
		getline(cin, lessID);
		string statement = "select lessons_id from LECTURERS_LESSONS ";
		statement += "where fullname = '"+fullName+"' and lessons_id = '"+lessID+"'; ";

		if (lessID == "exit")
			lectMenu();
		else if (lessID != "")
		{
			vector < vector<string> > temp;
			temp = db.query(statement);
			if (temp.size() != 0)
				check = false;
			else
				cout << "The lesson id not found! Please enter another lesson ID. " << endl;
		}
	}
	return lessID;
}

string Lecturers::getPtIdFromPLACETIME(string venueName, string timeSlot)
{
	string statement = "select pt_id from place_time ";
	statement += "where venue = '"+venueName+"' and strftime ('%Y-%m-%d %H:%M',timeslot) = '"+timeSlot+"';";
	vector<vector<string> > tempId = db.query(statement);
	return tempId[0].at(0);
}

double Lecturers::totalHours(string startDate, string endDate,string moduleCodeInput)
{
	vector<vector <string> > totalLessons = db.query("SELECT COUNT(l.lessons_id) FROM LESSONS l INNER JOIN PLACE_TIME pt ON l.pt_id = pt.pt_id  WHERE strftime ('%Y-%m-%d', timeslot) BETWEEN strftime ('%Y-%m-%d', '"+startDate+"') AND strftime ('%Y-%m-%d', '"+endDate+"') AND module_code = '"+moduleCodeInput+"';");
	return (atof(totalLessons[0][0].c_str()) * 3);
}
